---
title: GraphQL query best practices
description: Operation naming, GraphQL variables, and more
---

When creating queries and mutations, follow these best practices to get the most out of both GraphQL and Apollo tooling.

## Name all operations

These two queries fetch the same data:

```graphql
# Recommended ✅
query GetBooks {
  books {
    title
  }
}

# Not recommended ❌
query {
  books {
    title
  }
}
```

The first query is named `GetBooks`. The second query is **anonymous**.

You should define a name for _every_ GraphQL operation in your application. Doing so provides the following benefits:

- You clarify the purpose of each operation for both yourself and your teammates.
- You avoid unexpected errors when combining multiple operations in a single query document (an anonymous operation can only appear alone).
- You improve debugging output in both client _and_ server code, helping you identify exactly which operation is causing issues.
- [Apollo GraphOS Studio](/graphos/graphs/studio-features) provides helpful operation-level metrics, which require named operations.

## Use GraphQL variables to provide arguments

These two queries can both fetch a `Dog` object with ID `"5"`:

```graphql {2-3,10-11}
# Recommended ✅
query GetDog($dogId: ID!) {
  dog(id: $dogId) {
    name
    breed
  }
}

# Not recommended ❌
query GetDog {
  dog(id: "5") {
    name
    breed
  }
}
```

The first query uses a variable (`$dogId`) for the value of the `dog` field's required argument. This means you can use the query to fetch a `Dog` object with _any_ ID, making it much more reusable.

You pass variable values to `useQuery` (or `useMutation`) like so:

```js {11-15} title="dog.tsx"
const GET_DOG = gql`
  query GetDog($dogId: ID!) {
    dog(id: $dogId) {
      name
      breed
    }
  }
`;

function Dog({ id }) {
  const { loading, error, data } = useQuery(GET_DOG, {
    variables: {
      dogId: id,
    },
  });
  // ...render component...
}
```

### Disadvantages of hardcoded GraphQL arguments

Beyond reusability, hardcoded arguments have other disadvantages relative to variables:

#### Reduced cache effectiveness

If two otherwise identical queries have different hardcoded argument values, they're considered _entirely different operations_ by your GraphQL server's cache. The cache enables your server to _skip_ parsing and validating operations that it's encountered before, improving performance.

The server-side cache also powers features like [automatic persisted queries](/apollo-server/performance/apq/) and query plans in a [federated gateway](/federation/building-supergraphs/router/). Hardcoded arguments reduce the performance gains of these features and take up useful space in the cache.

#### Reduced information privacy

The value of a GraphQL argument might include sensitive information, such as an access token or a user's personal info. If this information is included in a query string, it's cached with the rest of that query string.

Variable values are _not_ included in query strings. You can also specify _which_ variable values (if any) are [included in metrics reporting](/apollo-server/api/plugin/usage-reporting/#sendvariablevalues) to Studio.

## Query only the data you need, where you need it

One of GraphQL's biggest advantages over a traditional REST API is its support for [declarative data fetching](/intro/benefits/#graphql-provides-declarative-efficient-data-fetching). Each component can (and should) query exactly the fields it requires to render, with no superfluous data sent over the network.

If instead your root component executes a single, enormous query to obtain data for all of its children, it might query on behalf of components that _aren't even rendered_ given the current state. This can result in a delayed response, and it drastically reduces the likelihood that the query's result can be reused by a [server-side response cache](/apollo-server/performance/caching/).

In the large majority of cases, a query such as the following should be divided into _multiple_ queries that are distributed among the appropriate components:

<ExpansionPanel title="Click to expand">

```graphql
# Not recommended ❌
query GetGlobalStatus {
  stores {
    id
    name
    address {
      street
      city
    }
    employees {
      id
    }
    manager {
      id
    }
  }
  products {
    id
    name
    price {
      amount
      currency
    }
  }
  employees {
    id
    role
    name {
      firstName
      lastName
    }
    store {
      id
    }
  }
  offers {
    id
    products {
      id
    }
    discount {
      discountType
      amount
    }
  }
}
```

</ExpansionPanel>

- If you have collections of components that _are_ always rendered together, you can use fragments to distribute the structure of a single query between them. See [Colocating fragments](./fragments/#colocating-fragments).
- If you're querying a list field that returns more items than your component needs to render, you should [paginate that field](../pagination/overview/).

## Query global data and user-specific data separately

Some fields return the exact same data regardless of which user queries them:

```graphql
# Returns all elements of the periodic table
query GetAllElements {
  elements {
    atomicNumber
    name
    symbol
  }
}
```

Other fields return _different_ data depending on which user queries them:

```graphql
# Returns the current user's documents
query GetMyDocuments {
  myDocuments {
    id
    title
    url
    updatedAt
  }
}
```

To improve the performance of your [server-side response cache](/apollo-server/performance/caching/), fetch these two types of fields in _separate queries_ whenever possible. By doing so, your server can cache just a _single_ response for a query like `GetAllElements` above, while caching separate responses for each user that executes `GetMyDocuments`.

## Set your app's `name` and `version` for metrics reporting (paid)

<Note>

This recommendation is _most_ pertinent to Studio organizations with a [paid plan](https://www.apollographql.com/pricing/), however it can be helpful for all apps.

</Note>

The constructor of `ApolloClient` accepts the `clientAwareness` option with `name` and `version` properties:

```js {4-7}
const client = new ApolloClient({
  link: new HttpLink({ uri: "http://localhost:4000/graphql" }),
  cache: new InMemoryCache(),
  clientAwareness: {
    name: "MarketingSite",
    version: "1.2",
  },
});
```

If you specify these values, Apollo Client automatically adds them to each operation request as HTTP headers (`apollographql-client-name` and `apollographql-client-version`).

Then if you've configured metrics reporting in Studio, Apollo Server includes your app's `name` and `version` in the operation traces it reports to Studio. This enables you to [segment metrics by client](/graphos/metrics/client-awareness/).
